#import "RNDetailView.h"
#import "NSCell+SRAdditions.h"
#import "RNConstants.h"

#define RNDetailViewIntercellSpacing 1.0f

static NSColor *insertionMarkerColor;
static NSUInteger insertionMarkerWidth = 2;
static CGFloat insertionMarkerCircleRadius = 3;

@implementation RNDetailView

@synthesize trackingRow = trackingRow_;
@synthesize trackingCell = trackingCell_;
@synthesize validatedDropNode = validatedDropNode_;
@synthesize validatedDropIndex = validatedDropIndex_;

+(void)initialize {
    insertionMarkerColor = [NSColor colorWithCalibratedRed:0.22 green:0.459 blue:0.843 alpha:1.0];
}

-(void)initializeDetailView {
    [self setTrackingRow:-1];
    [self setValidatedDropIndex:NSOutlineViewDropOnItemIndex];
}

-(id)initWithFrame:(NSRect)frame {
    if (!(self = [super initWithFrame:frame]))
        return nil;
    
    [self initializeDetailView];
    return self;
}

-(id)initWithCoder:(NSCoder *)coder {
    if (!(self = [super initWithCoder:coder]))
        return nil;
    
    [self initializeDetailView];
    return self;
}

-(void)awakeFromNib {
    [self setIntercellSpacing:NSMakeSize(3.0f /*The default*/, RNDetailViewIntercellSpacing)];
}

-(void)setValidatedDropIndex:(NSInteger)dropIndex {
    validatedDropIndex_ = dropIndex;
}

-(void)drawInsertionMarker {
    NSTreeNode *parentNode = [self validatedDropNode];
    NSTreeNode *childNodeAboveDropPoint = nil;
    if ([self validatedDropIndex] == 0)
        childNodeAboveDropPoint = parentNode;
    else
        childNodeAboveDropPoint = [[parentNode childNodes] objectAtIndex:[self validatedDropIndex] - 1];

    NSInteger upperRow = [self rowForItem:childNodeAboveDropPoint];
    NSRect upperRect = [self rectOfRow:upperRow];
    CGFloat midY = NSMaxY(upperRect) + ([self intercellSpacing].height / 2);
    NSRect detailRect = [self frame];
    NSBezierPath *insertionMarker = [NSBezierPath bezierPath];
    NSPoint rightPoint = NSMakePoint(NSMaxX(detailRect) - RNDetailViewBorderPadding, midY);
    NSPoint leftPoint = NSMakePoint(NSMinX(detailRect) + RNDetailViewBorderPadding + (RNDetailViewCellCornerRadius / 3), midY);
    NSPoint circleCenter = leftPoint;
    circleCenter.x -= insertionMarkerCircleRadius;
    [insertionMarker moveToPoint:rightPoint];
    [insertionMarker lineToPoint:leftPoint];
    [insertionMarker appendBezierPathWithArcWithCenter:circleCenter radius:insertionMarkerCircleRadius startAngle:0 endAngle:359];
    [insertionMarker setLineWidth:insertionMarkerWidth];
    [insertionMarkerColor setStroke];
    [insertionMarker stroke];
}

-(void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    if ([self validatedDropIndex] != NSOutlineViewDropOnItemIndex) 
        [self drawInsertionMarker];
}

-(void)updateTrackingAreas {
    for (NSTrackingArea *area in [self trackingAreas])
        [self removeTrackingArea:area];
    
    NSPoint mouseLocation = [self convertPoint:[[self window] convertScreenToBase:[NSEvent mouseLocation]] fromView:nil];
    NSRange visibleRows = [self rowsInRect:[self visibleRect]];
    for (NSUInteger row = visibleRows.location; row < NSMaxRange(visibleRows); row++ ) {
        NSCell *visibleCell = [self preparedCellAtColumn:0 row:row];
        if (![visibleCell respondsToSelector:@selector(addTrackingAreasForView:inRect:withUserInfo:mouseLocation:)]) 
            continue;
        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:row] forKey:RNRowKey];
        [visibleCell addTrackingAreasForView:self inRect:[self frameOfCellAtColumn:0 row:row] withUserInfo:userInfo mouseLocation:mouseLocation];
    }
}

- (void)mouseEntered:(NSEvent *)event {
    NSDictionary *userInfo = [event userData];
    NSNumber *row = [userInfo valueForKey:RNRowKey];
    if (!row) 
        return;
    NSInteger rowValue = [row integerValue]; 
    NSCell *cell = [self preparedCellAtColumn:0 row:rowValue];
    [self setTrackingRow:rowValue];
    [self setTrackingCell:[cell copy]];
    [[self trackingCell] setControlView:self];
    [[self trackingCell] mouseEntered:event];
    if (rowValue > 0)
        [self setNeedsDisplayInRect:[self rectOfRow:rowValue-1]];
}

- (void)mouseExited:(NSEvent *)event {
    NSDictionary *userInfo = [event userData];
    NSNumber *row = [userInfo valueForKey:RNRowKey];
    if (!row) 
        return;
    NSCell *cell = [self preparedCellAtColumn:0 row:[row integerValue]];
    [cell mouseExited:event];
    [self setTrackingCell:nil];
    [self setTrackingRow:-1];
    NSInteger rowValue = [row integerValue]; 
    if (rowValue > 0)
        [self setNeedsDisplayInRect:[self rectOfRow:rowValue-1]];
}

- (NSCell *)preparedCellAtColumn:(NSInteger)column row:(NSInteger)row {
    if (row == [self trackingRow]) {
        // TODO: THIS IS A BIT OF A HACK TO UPDATE THE TRACKING CELL - CAN THIS BE GENERALIZED?
        id object = [[self itemAtRow:[self trackingRow]] representedObject];
        id data = [object valueForKeyPath:@"objectDictionary"];
        [[self trackingCell] setObjectValue:data];
        return [self trackingCell];
    }
    return [super preparedCellAtColumn:column row:row];
}

- (void)updateCell:(NSCell *)aCell {
    if (aCell == [self trackingCell]) {
        [self setNeedsDisplayInRect:[self frameOfCellAtColumn:0 row:[self trackingRow]]];
    }
    [super updateCell:aCell];
}

- (void)highlightSelectionInClipRect:(NSRect)clipRect {
    // No-op.  Highlighting is done in the custom cells
}

-(NSRect)frameOfOutlineCellAtRow:(NSInteger)row {
    return NSZeroRect;
}

- (BOOL)inLiveResize {
    return NO;
}

-(void)keyDown:(NSEvent *)theEvent {
    NSString *characters = [theEvent characters];
    unichar character = [characters characterAtIndex:0];
    if (character == 0x0d) {  // Return
        [NSApp sendAction:@selector(editSelectedItem:) to:nil from:self];
    }
    else if (character == ' ') {
        [NSApp sendAction:@selector(toggleComplete:) to:nil from:self];
    }
    else if (character == NSLeftArrowFunctionKey) {
        [NSApp sendAction:@selector(decrementCount:) to:nil from:self];
    }
    else if (character == NSRightArrowFunctionKey) {
        [NSApp sendAction:@selector(incrementCount:) to:nil from:self];
    }
    else
        [super keyDown:theEvent];
}

- (BOOL)becomeFirstResponder {
    [self setNeedsDisplay:YES];
    return [super becomeFirstResponder];
}

- (BOOL)resignFirstResponder {
    [self setNeedsDisplay:YES];
    return [super resignFirstResponder];
}

- (void)draggingExited:(id < NSDraggingInfo >)sender {
    [self setValidatedDropNode:nil];
    [self setValidatedDropIndex:-1];
    [self setNeedsDisplay:YES];
    [super draggingExited:sender];
}

- (void)textDidEndEditing:(NSNotification *)aNotification {
	NSText *fieldEditor = [aNotification object];
	NSCell *editedCell = [self preparedCellAtColumn:0 row:[self editedRow]];
	id object = [editedCell representedObject];
	[object setValue:[[fieldEditor string] copy] forKey:RNTitleKey];
	[super textDidEndEditing:aNotification];
}

- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector {
	if (aSelector != @selector(cancelOperation:) && aSelector != @selector(insertNewline:))
		return NO;
	[[self window] makeFirstResponder:self];
	return YES;
}


@end
